package com.myblockchain.service.impl;

import com.alibaba.fastjson.JSON;
import com.myblockchain.utility.CryptoUtil;
import com.myblockchain.utility.RSACoder;
import com.myblockchain.service.TransactionService;
import com.myblockchain.service.model.Transaction;
import com.myblockchain.service.model.TransactionInput;
import com.myblockchain.service.model.TransactionOutput;
import org.springframework.stereotype.Service;


/**
 * @author Liu
 */
@Service
public class TransactionServiceImpl implements TransactionService {

    @Override
    public void sign(Transaction transaction, String privateKey, Transaction prevTx) {
        if (coinbaseTx(transaction)){
            return;
        }
        if (!prevTx.getId().equals(transaction.getTxIn().getTxId())){
            System.err.println("交易签名失败，当前交易输入引用的前一笔交易与传入的前一笔交易不匹配");
        }
        Transaction txClone = cloneTx(transaction);
//        前一笔交易的输出，就是这一笔交易的输入
//        对发送方和接受方的公钥以及这个交易做签名
        txClone.getTxIn().setPublicKey(prevTx.getTxOut().getPublicHashKey());
//        接收方的公钥hash在txOut中，已经被复制到clone中
        String sign = "";
        try {
            sign = RSACoder.sign(hash(txClone).getBytes(),privateKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        transaction.getTxIn().setSignature(sign);
    }

    @Override
    public boolean coinbaseTx(Transaction transaction) {
        return transaction.getTxIn().getTxId().equals("0") && transaction.getTxIn().getValue() == -1;
    }

    @Override
    public Transaction cloneTx(Transaction transaction) {
        TransactionInput trInput = TransactionInput.builder()
                .txId(transaction.getTxIn().getTxId())
                .value(transaction.getTxIn().getValue())
                .publicKey(null)
                .signature(null)
                .build();
        TransactionOutput trOut = TransactionOutput.builder()
                .value(transaction.getTxOut().getValue())
                .publicHashKey(transaction.getTxOut().getPublicHashKey())
                .build();
        return Transaction.builder()
                .id(transaction.getId())
                .txIn(trInput)
                .txOut(trOut)
                .build();
    }

    @Override
    public String hash(Transaction transaction) {
        return CryptoUtil.SHA256(JSON.toJSONString(transaction));
    }


    @Override
    public boolean verify(Transaction transaction, Transaction prevTx){
        if (coinbaseTx(transaction)){
            return true;
        }
        if (!prevTx.getId().equals(transaction.getTxIn().getTxId())){
//          交易验证失败
        }
        //得到当初签名的data
        Transaction txClone = cloneTx(transaction);
        txClone.getTxIn().setPublicKey(prevTx.getTxOut().getPublicHashKey());

        boolean res = false;
        try {
            //公钥、签名、信息用来验证签名
            //RSACoder.verify为密码学中的验证签名，之前提到过
            res = RSACoder.verify(hash(txClone).getBytes(), transaction.getTxIn().getPublicKey(), transaction.getTxIn().getSignature());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }
}
